


#include "common/linkage.h"
#include "i386/kernel/segment.h"
#include "linux/irq_vector.h"
	
	.extern do_devide_error
	.extern do_debug 
	.extern do_nmi 
	.extern do_int3 
	.extern do_overflow 
	.extern do_device_not_available 
	.extern do_coprocessor_segment_overrun
	.extern do_invalid_TSS
	.extern do_segment_not_present
	.extern do_stack_segment
	.extern do_general_protection
	.extern do_alignment_check 
	.extern do_page_fault
	.extern do_suprious_interrupt_bug
	.extern do_coprocessor_error
	.extern do_machine_check
	.extern do_IRQ

/*
* 保存各个寄存器的偏移地址
*/
EBX             = 0x00
ECX             = 0x04
EDX             = 0x08
ESI             = 0x0C
EDI             = 0x10
EBP             = 0x14
EAX             = 0x18
DS              = 0x1C
ES              = 0x20
ORIG_EAX        = 0x24
EIP             = 0x28
CS              = 0x2C
EFLAGS          = 0x30
OLDESP          = 0x34
OLDSS           = 0x38

CF_MASK         = 0x00000001
TF_MASK         = 0x00000100
IF_MASK         = 0x00000200
DF_MASK         = 0x00000400
NT_MASK         = 0x00004000
VM_MASK         = 0x00020000
	

#define SAVE_ALL		\
	cld;			\
	pushl	%es;		\
	pushl	%ds;		\
	pushl	%eax;		\
	pushl	%ebp;		\
	pushl	%edi;		\
	pushl	%esi;		\
	pushl	%edx;		\
	pushl	%ecx;		\
	pushl	%ebx;		\
	movl	$(__USER_DS), %edx;	\
	movl	%edx, %ds;		\
	movl	%edx, %es;

#define RESTORE_INT_REGS	\
	popl	%ebx;		\
	popl	%ecx;		\
	popl	%edx;		\
	popl	%esi;		\
	popl	%edi;		\
	popl	%ebp;		\
	popl	%eax;

#define  RESTORE_REGS		\
	RESTORE_INT_REGS;	\
1:	popl	%ds;		\
2:	popl	%es;		\
 .section .fixup, "ax";		\
3:	movl	$0, (%esp);	\
	jmp	1b;		\
4:	movl	$0, (%esp);	\
	jmp	2b;		\
.previous;			\
.section __exit_table, "a";	\
	.align 4;		\
	.long 1b, 3b;		\
	.long 2b, 4b;		\
.previous;

#define RESTORE_ALL		\
	RESTORE_REGS;		\
	addl	$4, %esp;	\
	iret;
.section __exit_table, "a"
	.align 4, 0x90
.previous
	/*
.section .fixup,"ax";		\
2:	sti;			\
	movl	$(__USER_DS), %edx;	\
	movl	%edx, %ds;	\
	movl	%edx, %es;	\
	movl	$11, %eax;	\
	call	do_exit;	\
.previous;			\
.section __exit_table, "a";	\
	.align 4;		\
	.long 1b, 2b;		\
.previous;
	*/

	

/*
* 初始化 interrupt 数组
*/
.data
.align 4, 0x90
ENTRY(interrupt)
.text
	
vector = 0
ENTRY(irq_entries_start)
.rept 	NR_IRQS
	.align 4, 0x90
1:	pushl	$vector
	jmp	common_interrupt
.data
	.align 4, 0x90
	.long 1b
.text
	vector=vector+1
.endr
	.align 4, 0x90
common_interrupt:
	/*
	* SAVE_ALL宏， 使得所有寄存器信息压栈，而栈顶指针
	* 可以当作pt_regs的指针使用。
	* 而在上面的 irq 可以通过栈顶指针及大小计算得到
	*/
	SAVE_ALL
	movl	%esp, %eax
	call	do_IRQ
	jmp	ret_from_intr

ret_from_intr:
	/*
	* 根据 CS 的标志位判断中断从哪里发生
	* 如果是内核态中断，则调用 resume_kernel ;
	* 如果是用户态则调用 resume_userspace 返回
	*/
	movl	EFLAGS(%esp), %eax
	movb	CS(%esp), %al
	testl	$(VM_MASK | 3), %eax
	jz	resume_kernel
ENTRY(resume_userspace)
	ud2  // no implement
	jmp	restore_all

ENTRY(resume_kernel)
	jmp	restore_all

restore_all:
	RESTORE_ALL
/*
*  处理CPU异常
*/
	.code32
	.section "init.entry32", "ax"
	.align 4
	/*
	* 出错处理
	*/
error_code:
	pushl	%ds
	pushl	%eax
	xor	%eax, %eax
	pushl	%ebp
	pushl	%edi
	pushl	%esi
	pushl	%edx
	decl	%eax
	pushl	%ecx
	pushl	%ebx
	cld
	movl	%es, %ecx
	movl	ES(%esp), %edi	      # function pointer
	movl	ORIG_EAX(%esp), %edx  # error code
	movl	%eax, ORIG_EAX(%esp)
	movl	%ecx, ES(%esp)
	movl	$(__USER_DS), %ecx
	movl	%ecx, %ds
	movl	%ecx, %es
	movl	%esp, %eax            # pt_regs pointer
	call	*%edi
	jmp	ret_from_exception

ret_from_exception:
1: 	jmp 1b
2:	RESTORE_INT_REGS
	iret
.section __exit_table, "a"
	.align 4
	.long 1b, 2b

ENTRY(divide_error)	pushl	$0
	pushl	$do_divide_error
	jmp	error_code

ENTRY(debug)
	pushl $0
	pushl $do_debug
	jmp error_code
	
ENTRY(nmi)
	pushl $0
	pushl $do_nmi
	jmp error_code

/* break pointers*/
ENTRY(int3)
	pushl $0
	pushl $do_int3
	jmp error_code
	
ENTRY(overflow)
	pushl $0
	pushl $do_overflow
	jmp error_code
	
ENTRY(bounds)
	pushl $0
	pushl $do_bounds
	jmp error_code
	
ENTRY(invalid_op)
	pushl $0
	pushl $do_invalid_op
	jmp error_code
	
ENTRY(device_not_available)
	pushl $0
	pushl $do_device_not_available
	jmp error_code
	
ENTRY(coprocessor_segment_overrun)
	pushl $0
	pushl $do_coprocessor_segment_overrun
	jmp error_code
	
ENTRY(invalid_TSS)
	pushl $do_invalid_TSS
	jmp error_code
	
ENTRY(segment_not_present)
	pushl $do_segment_not_present
	jmp error_code
	
ENTRY(stack_segment)
	pushl $do_stack_segment
	jmp error_code
	
ENTRY(general_protection)
	pushl $do_general_protection
	jmp error_code
	
ENTRY(alignment_check)
	pushl $do_alignment_check
	jmp error_code
	
ENTRY(page_fault)
	pushl $do_page_fault
	jmp error_code

ENTRY(spurious_interrupt_bug)
	pushl $do_spurious_interrupt_bug
	jmp error_code

ENTRY(coprocessor_error)
	pushl	$do_coprocessor_error
	jmp	error_code
	
ENTRY(machine_check)
	pushl $0
	pushl $do_machine_check
	jmp error_code
	
